﻿//using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;
using Nemerle.Data;
using Nemerle.Data.Function.Functions;

using System;
using System.Collections.Generic;
using System.Linq;

using FsCheck.Fluent;

namespace QCTests
{
  /// <summary>
  /// Description of FunctionsTest.
  /// </summary>
  module TestFunctions
  {
    public Run() : void
    {
      Spec.ForAny((x : int, y : int) => Apply(y / _, x) == y / x)
        .When((x, _) => x != 0)
        .QuickCheck("Apply");
      
      Spec.ForAny((x : int, y : int) => Const(x)(y) == x )
        .QuickCheck("Const");
        
      Spec.ForAny((x : int, y : int) => Curry(_ / _)(x)(y) == x / y )
        .When((_, y) => y != 0)
        .QuickCheck("Curry");  
        
      Spec.ForAny((x : int, y : int) => UnCurry(Curry(_ / _))(x, y) == x / y )
        .When((_, y) => y != 0)
        .QuickCheck("Curry/UnCurry");  
      
      def f' = f => x => if (x > 0) x * f(x - 1) else 1;
      
      def g' = g => x => if (x > 0) x + g(x - 1) else 0;
      
      Spec.For(Any.IntBetween(1, 12), x => Fix(f')(x) == $[1 .. x].Reduce(_*_))
        .QuickCheck("Fix_1");
        
      Spec.ForAny(x : int => Fix(g')(x) == $[1 .. x].Fold(0, _+_))
        .QuickCheck("Fix_2");
        
      Spec.ForAny((x : int, y : int) => Flip(Flip(_ / _))(x, y) == x / y )
        .When((_, y) => y != 0)
        .QuickCheck("Flip_1");
        
      Spec.ForAny((x : int, y : int) => Flip(Flip(Curry(_ / _)))(x)(y) == x / y )
        .When((_, y) => y != 0)
        .QuickCheck("Flip_2");
        
      Spec.ForAny(xs : array[int] => xs.Map(Id).SequenceEqual(xs))
        .QuickCheck("Id");
        
      Spec.ForAny((x : int, y : int) => On(_/_, _ - x*2)(x,y) == (x - x*2) / (y - x*2) )
        .When((x, y) => (y - x*2) != 0)
        .QuickCheck("On_1");

      Spec.ForAny((x : int, y : int) => On(_/_, Id)(x,y) == x / y )
        .When((_, y) => y != 0)
        .QuickCheck("On_2");

      Spec.ForAny((x : int, y : int) => On(On(_/_, _ - x*2), _ - y*2)(x,y) == On(_/_, (_ - y*2) >> (_ - x*2))(x,y) )
        .When((x, y) => (y - y * 2 - x * 2) != 0)
        .QuickCheck("On_3");
    }
  }
}
